#include <stdio.h>//标准输入输出
#include <stdlib.h>//函数库
#include <string.h>//字符串操作
#include <dirent.h> //目录名获取配合DIR
#include <assert.h>//断言
#include <sys/stat.h>//文件状态操作
#include <sys/types.h>//获取pid等
#include <unistd.h>//文件操作
#include <fcntl.h> //文件控制操作
#include <sys/types.h> //获取pid等
#include <sys/wait.h> //等待子进程结束
#include <time.h> //时间获取
#include <sys/ipc.h> //进程通信
#include <sys/msg.h> //消息队列
#include <sys/shm.h> //共享内存
#include <signal.h> //信号处理
#include <pthread.h> //线程
#include <sys/types.h>//获取pid等
#include <sys/socket.h>//socket
#include <netinet/in.h>//socket
#include <arpa/inet.h>//socket
#include <sys/epoll.h>//epoll
#include "cJSON.h"

// 定义互斥锁，确保更新和检查心跳时间时不会产生竞态条件
pthread_mutex_t heartbeat_lock = PTHREAD_MUTEX_INITIALIZER;

struct msg {
	char operator[10];
	int number1;
	int number2;
	int result;
};

// 客户端结构体，记录最后收到心跳包的时间
struct client_info {
	int fd;
	time_t last_heartbeat;
};

// 记录客户端信息的数组
struct client_info clients[10];
//初始化客户端信息
void init_client_info() {
	for (int i = 0; i < 10; i++) {
		clients[i].fd = -1;
		clients[i].last_heartbeat = 0;
	}
}


//声明：
void unpack(char* buf, int listenfd);
char* fun(struct msg* k);
void* send_heartbeat(void* arg);
void update_client_heartbeat(int fd);
void remove_client(int fd);
void handle_client_message(int listenfd, char* buf);


//epoll实现计算服务器
int main(int argc, char *argv[])
{
	int sock = 0;
	int ret = 0;
	int listenfd = 0;
	struct sockaddr_in addr;
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		exit(-1);
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(6981);//-----------------------------------------------------------------------------------------
	addr.sin_addr.s_addr = inet_addr("192.168.48.128");

	ret = bind(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr));
	if (ret == -1)
	{
		perror("bind");
		exit(-1);
	}
	listen(sock, 5);


	//创建epoll
	int epollfd = 0;
	epollfd = epoll_create1(0);
	if (epollfd == -1) {
		perror("epoll_create1");
		exit(EXIT_FAILURE);
	}

	//添加监听事件
	struct epoll_event ev;
	memset(&ev, 0, sizeof(ev));
	ev.events = EPOLLIN;
	ev.data.fd = sock;
	ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &ev);
	if (ret == -1) {
		perror("epoll_ctl");
		exit(EXIT_FAILURE);
	}


	// 创建心跳包线程
	pthread_t tid;
	init_client_info();
	pthread_create(&tid, NULL, send_heartbeat, &epollfd);


	//监控套接字集合 
	int nfds = 0;
	struct epoll_event events[10];
	// epoll 处理循环
	while (1) {
		nfds = epoll_wait(epollfd, events, 10, -1); // 使用阻塞模式，等待事件发生
		if (nfds == -1) {
			perror("epoll_wait");
			exit(EXIT_FAILURE);
		}

		for (int i = 0; i < nfds; i++) {
			if (events[i].data.fd == sock) {
				// 处理新连接
				struct sockaddr_in client_addr;
				socklen_t len = sizeof(client_addr);
				int listenfd = accept(sock, (struct sockaddr*)&client_addr, &len);
				if (listenfd == -1) {
					perror("accept");
					exit(EXIT_FAILURE);
				}

				// 添加新客户端到epoll和客户端列表
				struct epoll_event ev;
				ev.events = EPOLLIN;
				ev.data.fd = listenfd;
				ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev);
				if (ret == -1) {
					perror("epoll_ctl");
					exit(EXIT_FAILURE);
				}

				pthread_mutex_lock(&heartbeat_lock); // 加锁，防止竞态条件
				for (int j = 0; j < 10; j++) {
					if (clients[j].fd == -1) {
						clients[j].fd = listenfd;
						clients[j].last_heartbeat = time(NULL); // 初始化心跳时间
						break;
					}
				}
				pthread_mutex_unlock(&heartbeat_lock); // 解锁
			}
			else {
				// 处理已连接客户端的消息
				char buf[1024] = { 0 };
				int listenfd = events[i].data.fd;
				int ret = recv(listenfd, buf, sizeof(buf), 0);

				if (ret > 0) {
					handle_client_message(listenfd, buf); // 正常处理消息并更新心跳时间
				}
				else if (ret == 0) {
					// 客户端关闭
					printf("客户端%d关闭\n", listenfd);
					epoll_ctl(epollfd, EPOLL_CTL_DEL, listenfd, NULL);
					close(listenfd);
					remove_client(listenfd); // 从客户端列表中移除
				}
				else {
					perror("recv");
				}
			}
		}
	}
	close(sock);
	return 0;
}


//解析json
void unpack(char *buf,int listenfd) {
	struct msg k;
	int ret = 0;
	cJSON* json = NULL;
	json = cJSON_Parse(buf);
	if (json == NULL) {
		printf("解析error\n");
	}

	cJSON* num1 = NULL;
	num1 = cJSON_GetObjectItem(json, "number1");
	if (num1 == NULL) {
		printf("读取error\n");
	}
	if (num1->type == cJSON_Number) {
		k.number1 = num1->valueint;
	}

	cJSON* num2 = NULL;
	num2 = cJSON_GetObjectItem(json, "number2");
	if (num2 == NULL) {
		printf("读取error\n");
	}
	if (num2->type == cJSON_Number) {
		k.number2 = num2->valueint;
	}
	cJSON* op = NULL;
	op = cJSON_GetObjectItem(json, "operator");
	if (op == NULL) {
		printf("读取error\n");
	}
	if (op->type == cJSON_String) {
		strcpy(k.operator, op->valuestring);
		if (strcmp(k.operator, "add") == 0) {
			k.result = (k.number1) + (k.number2);
			char* dest = fun(&k);
			ret = send(listenfd, dest, strlen(dest), 0);
			if (ret == -1) {
				perror("send");
			}
		}
		else if (strcmp(k.operator, "sub") == 0) {
			k.result = (k.number1) - (k.number2);
			char* dest = fun(&k);
			ret = send(listenfd, dest, strlen(dest), 0);
			if (ret == -1) {
				perror("send");
			}
		}
		else if (strcmp(k.operator, "mul") == 0) {
			k.result = (k.number1) * (k.number2);
			char* dest = fun(&k);
			ret = send(listenfd, dest, strlen(dest), 0);
			if (ret == -1) {
				perror("send");
			}
		}
		else if (strcmp(k.operator, "div") == 0) {
			k.result = (k.number1) / (k.number2);
			char* dest = fun(&k);
			ret = send(listenfd, dest, strlen(dest), 0);
			if (ret == -1) {
				perror("send");
			}
		}
	}
	cJSON_Delete(json);
}

char* fun(struct msg* k) {
	cJSON* json = NULL;
	json = cJSON_CreateObject();
	cJSON_AddNumberToObject(json, "result", k->result);
	char* dest = cJSON_Print(json);
	printf("dest:%s\n", dest);
	return dest;//记得返回dest！！！
}


// 更新客户端心跳时间
void update_client_heartbeat(int fd) {
	pthread_mutex_lock(&heartbeat_lock); // 加锁，防止竞态条件
	for (int i = 0; i < 10; i++) {
		if (clients[i].fd == fd) {
			clients[i].last_heartbeat = time(NULL); // 更新心跳时间
			break;
		}
	}
	pthread_mutex_unlock(&heartbeat_lock); // 解锁
}

// 处理客户端消息，确保所有收到的数据都更新心跳时间
void handle_client_message(int listenfd, char* buf) {
	if (strstr(buf, "\"type\":\"heartbeat\"") != NULL) {
		update_client_heartbeat(listenfd); // 如果是心跳包，更新心跳时间
	}
	else {
		unpack(buf, listenfd); // 处理其他数据
		update_client_heartbeat(listenfd); // 无论什么数据，更新心跳时间
	}
}

// 线程函数：定期发送心跳包并检查客户端超时
void* send_heartbeat(void* arg) {
	char timeout_msg[1024] = { 0 };
	strcpy(timeout_msg, "{\"type\":\"timeout\",\"message\":\"您已超时，服务器将关闭连接。\"}");//发送给客户端JSON，已经超时结束!!!
	int epollfd = *(int*)arg;
	int ret = 0;

	while (1) {
		sleep(1); // 每秒检测一次
		time_t now = time(NULL);

		pthread_mutex_lock(&heartbeat_lock); // 加锁，防止竞态条件
		for (int i = 0; i < 10; i++) {
			if (clients[i].fd != -1 && now - clients[i].last_heartbeat > 15) {
				printf("客户端%d超时，关闭连接\n", clients[i].fd);

				// 发送超时消息给客户端
				ret = send(clients[i].fd, timeout_msg, strlen(timeout_msg), 0);
				if (ret == -1) {
					perror("send");
				}

				// 关闭连接
				epoll_ctl(epollfd, EPOLL_CTL_DEL, clients[i].fd, NULL);
				close(clients[i].fd);
				remove_client(clients[i].fd);
			}
		}
		pthread_mutex_unlock(&heartbeat_lock); // 解锁
	}
	return NULL;
}


// 移除客户端信息
void remove_client(int fd) {
	for (int i = 0; i < 10; i++) {
		if (clients[i].fd == fd) {
			clients[i].fd = -1;
			break;
		}
	}
}

